package com.wetool.service.invoicing;

import java.math.BigDecimal;
import java.util.ArrayList;
import java.util.List;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import com.wetool.Constant;
import com.wetool.common.commodity.CommodityResult;
import com.wetool.common.model.Message;
import com.wetool.entity.Commodity;
import com.wetool.entity.invoicing.InventoryRecord;
import com.wetool.entity.invoicing.InventoryRecordCommodity;
import com.wetool.entity.invoicing.InvoicingCommodity;
import com.wetool.entity.invoicing.InvoicingRecord;
import com.wetool.exception.CommodityNotFindException;
import com.wetool.jpa.CommodityRepo;
import com.wetool.jpa.invoicing.InventoryRecordRepo;
import com.wetool.model.enums.OutOfStorage;
import com.wetool.model.enums.Status;
import com.wetool.model.invoicing.InventoryRecordAdd;
import com.wetool.model.invoicing.InventoryRecordModify;
import com.wetool.model.invoicing.SearchParam;
import com.wetool.service.commodity.RuleCheckService;
import com.wetool.spec.invoicing.InventoryRecordSpec;
import com.wetool.utils.Arith;
import com.wetool.utils.BeanUtils;
import com.wetool.utils.BillNoUtils;

@Service
public class InventoryService {

	private static final Logger logger = LogManager.getLogger(InventoryService.class);

	@Autowired
	private BillNoUtils billNoUtils;
	
	@Autowired
	private RuleCheckService ruleCheckService;
	
	@Autowired
	private CommodityRepo commodityRepo;
	
	@Autowired
	private SupplierService supplierService;

	@Autowired
	private InventoryRecordRepo inventoryRecordRepo;

	@Autowired
	private InventoryCommodityService inventoryCommodityService;

	@Autowired
	private InvoicingCommodityNewService invoicingCommodityNewService;

	/**
	 * id 查询出入库记录
	 * @param id
	 */
	public InventoryRecord getById(Long id) {
		logger.info("编号查询出入库记录 . 参数【{}】", id);
		InventoryRecord inventoryRecord = inventoryRecordRepo.findOne(id);
		logger.info("编号查询出入库记录 . 返回出入库记录【{}】", inventoryRecord);
		return inventoryRecord;
	}
	
	/**
	 * 多条件查询
	 * @param searchParam
	 * @param p
	 * @return
	 */
	public Page<InventoryRecord> findAll(SearchParam searchParam, Pageable p){
		logger.info("多条件查询列表 . 查询条件【{}】", searchParam);
		InventoryRecordSpec spec = new InventoryRecordSpec(searchParam);
		Page<InventoryRecord> page = inventoryRecordRepo.findAll(spec, p);// 条件查询
		// 通过Page 对象获取List集合
		page.getContent().stream().forEach(ic -> {
			this.getName(ic);
			ic.setCommoditys(null);// 字段不展示
		});
		return page;
	}
	
	/**
	 * 查询入库单详情
	 * @param id入库单ID
	 * @return StorageModify
	 * @throws StorageNotFindException 
	 */
	public Message<InventoryRecordModify> findOne(Long id) {
		InventoryRecordModify inventoryRecordModify = new InventoryRecordModify();
		InventoryRecord inventoryRecord = inventoryRecordRepo.findOne(id);// 查询入库信息
		if (inventoryRecord == null || inventoryRecord.getIsDeleted() != false) {
			logger.debug("入库信息业务处理(查询入库单详情) 入库信息不存在或逻辑删除");
			return new Message<>(CommodityResult.SHGOPNOTLOGIN);
		}
		BeanUtils.copyProperties(inventoryRecord, inventoryRecordModify);// 复制属性值在展示对象
		return new Message<>(CommodityResult.SUCCESS, inventoryRecordModify);
	}
	
	/**
	 * 添加出入库单据
	 * @param inventoryRecordAdd
	 * @return
	 * @throws CommodityNotFindException 
	 */
	public Message<InventoryRecord> saveInventoryRecord(InventoryRecordAdd inventoryRecordAdd) throws CommodityNotFindException{
		logger.info("添加出入库单据 . 添加出入库对象【{}】", inventoryRecordAdd);
		InventoryRecord inventoryRecord = new InventoryRecord();
		BeanUtils.copyProperties(inventoryRecordAdd, inventoryRecord);//属性复制
		List<InventoryRecordCommodity> ircs = inventoryCommodityService.copy(inventoryRecordAdd.getCommoditys());
		/* 出入库单据提交对库存修改 */
		if (inventoryRecordAdd.getStatus() == Status.ORDERCOMMIT) {
			ircs = inventoryCommodityService.save(ircs, inventoryRecord.getShopId(), inventoryRecord.getSupplierId(), inventoryRecord.getOutOfStorage());
		}
		inventoryRecord.setCommoditys(ircs);//添加出入库内容明细
		logger.info("添加出入库单据 . 保存出入库单据【{}】", inventoryRecord);
		inventoryRecordRepo.save(inventoryRecord);
		return new Message<>(CommodityResult.SUCCESS,inventoryRecord);
	}
	
	/**
	 * 修改出入库记录
	 * @param inventoryRecord
	 * @param inventoryRecordModify
	 * @return
	 * @throws CommodityNotFindException
	 */
	public Message<?> updateInventoryRecord(InventoryRecord inventoryRecord, InventoryRecordModify inventoryRecordModify) throws CommodityNotFindException {
		logger.info("添加出入库单据 . 添加出入库对象【{}】", inventoryRecordModify);
		BeanUtils.copyProperties(inventoryRecordModify, inventoryRecord);//属性复制
		inventoryRecord.setCommoditys(null);
		List<InventoryRecordCommodity> ircs = inventoryCommodityService.copy(inventoryRecordModify.getCommoditys());
		/* 出入库单据提交对库存修改 */
		if (inventoryRecordModify.getStatus() == Status.ORDERCOMMIT) {
			ircs = inventoryCommodityService.save(ircs, inventoryRecord.getShopId(), inventoryRecord.getSupplierId(), inventoryRecord.getOutOfStorage());
		}
		inventoryRecord.setCommoditys(ircs);
		logger.info("添加出入库单据 . 保存出入库单据【{}】", inventoryRecord);
		inventoryRecordRepo.save(inventoryRecord);
		inventoryCommodityService.deletedByIdNull();
		return new Message<>(CommodityResult.SUCCESS);
	}
	
	/**
	 * 添加商品信息时同时入库
	 * @param commodity
	 * @param shopId
	 * @param supplierId
	 * @return
	 */
	public Message<?> addInventoryRecord(Commodity commodity, Long shopId, Long supplierId) {
		logger.info("添加商品信息入库 . 参数 商品详情【{}】, 店铺id【{}】, 供应商id【{}】", commodity, shopId, supplierId);
		Message<InvoicingCommodity> message = invoicingCommodityNewService.findOrAdd(commodity, shopId, supplierId,commodity.getInventoryNumber());
		logger.info("添加商品信息入库 . 参数 库存信息【{}】", message);
		InvoicingCommodity ico = message.getData();
		InventoryRecord inventoryRecord = null;
		/* 库存数为０时不创建入库记录 */
		if (ico.getInventoryNumber() == 0) {
			return new Message<>(CommodityResult.SUCCESS);
		}
		/* 商品信息添加入库详情记录 */
		InventoryRecordCommodity inventoryRecordCommodity = new InventoryRecordCommodity(commodity.getBuyingPrice(),
				commodity.getInventoryNumber(), commodity.getBarcode(), commodity.getName(),
				commodity.getSpecification(), commodity.getUnit(), commodity.getId(), ico.getInventoryNumber());
		String no = billNoUtils.getBillNo(Constant.WARE_IN, shopId);//创建入库单号
		List<InventoryRecordCommodity> list = new ArrayList<InventoryRecordCommodity>();
		list.add(inventoryRecordCommodity);
		inventoryCommodityService.save(list);//保存入库记录信息
		Double totalPrice = Arith.mul(inventoryRecordCommodity.getCommodityNumber(), inventoryRecordCommodity.getPrice().doubleValue());
		totalPrice = Arith.round(totalPrice, 2);
		inventoryRecord = new InventoryRecord(no, null, 4L, list, supplierId, shopId, Status.ORDERCOMMIT, null, OutOfStorage.STORAGE,
				new BigDecimal(totalPrice));
		logger.info("设置入库记录【{}】 ", inventoryRecord);
		inventoryRecord = inventoryRecordRepo.saveAndFlush(inventoryRecord);
		return new Message<>(CommodityResult.SUCCESS, inventoryRecord);
	}

	/**
	 * 查询库存成本（移动加权平均法）
	 * @param shopId店铺id
	 * @param commodityId商家库商品id
	 * @return
	 */
	public Double getBuyingCost(Long shopId, Long commodityId) {
		logger.info("获取库存成本 . 参数 店铺id【{}】, 商品id【{}】", shopId, commodityId);
		List<InvoicingRecord> irs = inventoryRecordRepo.findByCommId(commodityId, shopId, OutOfStorage.STORAGE, 4L,Status.ORDERCOMMIT);
		Double countNumber = 0D;// 采购总数
		Double countPrice = 0D;// 采购总金额
		Double price = 0D;
		logger.info("获取库存成本 . 获取商品采购入库记录集合【{}】", irs);
		if (irs == null || irs.isEmpty()) {//无入库记录
			Commodity co = commodityRepo.findOne(commodityId);
			/* 获取库存信息 */
			Message<InvoicingCommodity> message = invoicingCommodityNewService.findOrAdd(co, shopId, null,0D);
			InvoicingCommodity ic = message.getData();
			/* 非空判断 */
			countNumber = ic.getInventoryNumber() == null ? 0D : ic.getInventoryNumber();
			countPrice = co.getBuyingPrice() == null ? new BigDecimal(0).doubleValue() : co.getBuyingPrice().doubleValue();
			/* 无入库记录计算库存成本 */
			Double buyingCost = ic != null ? Arith.round(Arith.mul(countNumber, countPrice), 2) : 0D;// 金额保留两位小数
			return buyingCost;
		}
		for (InvoicingRecord invoicingRecord : irs) {
			countNumber = Arith.add(countNumber, invoicingRecord.getNumber());//入库单对应商品数量累加
			countPrice = Arith.add(countPrice, invoicingRecord.getPrice());//入库单对应进货金额累加
		}
		if (countPrice != 0D) {
			price = Arith.div(countPrice, countNumber, 2);//获取平均金额
		}
		logger.info("获取库存成本 . 采购总数【{}】, 采购总金额【{}】, 平均金额【{}】", countNumber, countPrice, price);
		return Arith.round(Arith.mul(price, countNumber), 2);// 金额保留两位小数
	}

	/**
	 * 预售成本
	 * @param shopId店铺id
	 * @param commodityId商家库商品id
	 * @return
	 */
	public Double getSellingPrice(Long shopId, Long commodityId) {
		/* 获取库存信息 */
		InvoicingCommodity ic = invoicingCommodityNewService.getByCommodityIdAndShopId(commodityId, shopId);
		/* 属性默认为空设置默认值 */
		if (ic == null) {
			return 0D;
		}
		Double number = ic.getInventoryNumber() == null ? 0D : ic.getInventoryNumber();
		BigDecimal price = ic.getCommodity().getSellingPrice() == null ? new BigDecimal(0) : ic.getCommodity().getSellingPrice();
		logger.info("获取预售成本 . 预售总数【{}】, 采购总金额【{}】", number, price);
		return Arith.round(Arith.mul(number, price.doubleValue()), 2);
	}
	
	/**
	 * 查询供应商名称
	 * @param page
	 */
	public void getName(InventoryRecord page) {
		Long id = page.getSupplierId();
		if (id != null) {
			String name = supplierService.getName(id);
			page.setSupplierName(name);
		}
	}
	
	/**
	 * 删除出入库单据
	 * @param id
	 */
	public Message<?> delete(Long id) {
		InventoryRecord inventoryRecord = inventoryRecordRepo.findOne(id);
		logger.info("删除出入库单据 . 出入库编号【{}】, 查询详细信息【{}】", id , inventoryRecord);
		/* 删除出入库单据前查询是否符合规则 */
		Message<?> message = ruleCheckService.inventoryRecordDeletedCheck(inventoryRecord);
		if (message.getCode() != 0) {
			return message;
		}
		inventoryRecord.setIsDeleted(true);
		inventoryRecordRepo.save(inventoryRecord);
		logger.info("删除出入库单据 成功");
		return message;
	}

	/**
	 * 保存出入库记录实体
	 * @param placingAdd
	 * @return
	 */
	public InventoryRecord save(InventoryRecord inventoryRecord) {
		return inventoryRecordRepo.saveAndFlush(inventoryRecord);
	}
	
	/**
	 * 供应商对应的入库纪录数
	 * @param supplierId
	 * @param shopId
	 * @return
	 */
	public Long countBySupplierIdAndShopId(Long supplierId, Long shopId) {
		return inventoryRecordRepo.countBySupplierIdAndShopIdAndIsDeletedAndOutOfStorageAndTypeNotAndTypeNot(supplierId,shopId,false,OutOfStorage.STORAGE,7L,8L);
	}
}
